using System;
using System.Net;
using System.ServiceModel;
using System.Web.Script.Serialization;
using System.Web.Services.Protocols;

namespace Salient.Web
{
    ///<summary>
    ///</summary>
    public class WebRequestException : Exception
    {
        private WebRequestException(string message, Exception innerException)
            : base(message, innerException)
        {
            if (innerException is WebException)
            {
                HttpWebResponse response = (HttpWebResponse)((WebException)innerException).Response;
                StatusCode = response.StatusCode;
                StatusDescription = response.StatusDescription;
            }

        }
        ///<summary>
        ///</summary>
        public string Type { get; private set; }

        ///<summary>
        ///</summary>
        public WebExceptionDetail Detail { get; private set; }

        ///<summary>
        ///</summary>
        public HttpStatusCode StatusCode { get; private set; }

        ///<summary>
        ///</summary>
        public string StatusDescription { get; private set; }

        ///<summary>
        ///</summary>
        public WebExceptionStatus Status
        {
            get { return InnerException.Status; }
        }

        ///<summary>
        ///</summary>
        public new WebException InnerException
        {
            get { return (WebException)base.InnerException; }
        }

        ///<summary>
        ///</summary>
        public WebErrorType ErrorType { get; private set; }

        ///<summary>
        ///</summary>
        ///<param name="innerException"></param>
        ///<returns></returns>
        public static WebRequestException Create(WebException innerException)
        {
            WebRequestException result =
                Create(innerException, innerException.Response.GetResponseStream().Text());
            return result;
        }



        private static WebRequestException Create(Exception innerException, string text)
        {
            WebExceptionDetail detail = WebExceptionDetail.Create(text);
            WebRequestException result = new WebRequestException(detail.Message, innerException)
                {
                    Detail = detail,
                    ErrorType = detail.ErrorType,
                    Type = detail.Type
                };

            return result;
        }

        ///<summary>
        ///</summary>
        ///<param name="innerException"></param>
        ///<returns></returns>
        public static WebRequestException Create(SoapException innerException)
        {
            WebRequestException result = CreateSoap(innerException);
            return result;
        }

        ///<summary>
        ///</summary>
        ///<param name="innerException"></param>
        ///<returns></returns>
        public static WebRequestException Create(FaultException innerException)
        {
            if (innerException is FaultException<ExceptionDetail>)
            {
                // if includeExceptionDetailInFaults is true, we get details

                return Create((FaultException<ExceptionDetail>)innerException);
            }
            // otherwise nuttin
            WebRequestException result = CreateSoap(innerException);
            return result;
        }


        ///<summary>
        ///</summary>
        ///<param name="innerException"></param>
        ///<returns></returns>
        public static WebRequestException Create(FaultException<ExceptionDetail> innerException)
        {
            ExceptionDetail originalDetail = innerException.Detail;
            WebExceptionDetail copy;
            CopyExceptionDetail(originalDetail, out copy);

            WebRequestException result = new WebRequestException(copy.Message, innerException)
                {
                    Detail = copy,
                    ErrorType = copy.ErrorType,
                    Type = copy.Type
                };

            return result;
        }

        /// <summary>
        /// clever is overrated. just do the work. ;-)
        /// </summary>
        private static void CopyExceptionDetail(ExceptionDetail originalDetail, out WebExceptionDetail copy)
        {
            copy = new WebExceptionDetail
                {
                    ErrorType = WebErrorType.WCF,
                    Message = originalDetail.Message,
                    Type = originalDetail.Type,
                    StackTrace = originalDetail.StackTrace
                };
            if (originalDetail.InnerException != null)
            {
                WebExceptionDetail inner;
                CopyExceptionDetail(originalDetail.InnerException, out inner);
                copy.InnerException = inner;
            }

        }

        ///<summary>
        /// An .asmx when called with a WebReference or a ServiceReference it will return exception detail in the .Message property of the thrown exception
        /// 
        /// System.Web.Services.Protocols.SoapException: Server was unable to process request. ---> System.NotImplementedException: Intentional ---> System.ArgumentNullException: inner
        /// Parameter name: arg
        ///    at TestSite.Services.ScriptService.ThrowInner() in C:\Projects\salient\Releases\TestingWithVSDevServer_v1\TestSite\Services\ScriptService.asmx.cs:line 45
        ///    at TestSite.Services.ScriptService.ThrowException() in C:\Projects\salient\Releases\TestingWithVSDevServer_v1\TestSite\Services\ScriptService.asmx.cs:line 29
        ///    --- End of inner exception stack trace ---
        ///    at TestSite.Services.ScriptService.ThrowException() in C:\Projects\salient\Releases\TestingWithVSDevServer_v1\TestSite\Services\ScriptService.asmx.cs:line 33
        ///    --- End of inner exception stack trace ---   
        ///</summary>
        /// <param name="innerException"></param>
        /// <returns></returns>
        private static WebRequestException CreateSoap(Exception innerException)
        {
            string text = innerException.Message;
            // we need to trim off the generic SoapException
            const string soapExceptionPrefix = "System.Web.Services.Protocols.SoapException: Server was unable to process request. ---> ";
            if (text.StartsWith(soapExceptionPrefix))
            {
                text = text.Substring(soapExceptionPrefix.Length);
            }

            var result = Create(innerException, text);
            return result;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            string str2;
            string message = this.Message;
            var className = typeof (WebRequestException).FullName;
            if (string.IsNullOrEmpty(message))
            {
                str2 = String.Format("{0}: ({1})", className, ErrorType);
            }
            else
            {
                str2 = String.Format("{0}: ({1}){2}", className, ErrorType, message);
            }
            if (InnerException != null)
            {
                str2 = String.Format("{0} ---> {1}{2}   -- end of inner stack trace --", str2, InnerException, Environment.NewLine);
            }
            if (StackTrace != null)
            {
                str2 = str2 + Environment.NewLine + StackTrace;
            }
            return str2;
        }



    }
}